#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "hashFns.c"

#define FILTER_SIZE 100
#define NUM_HASHES 7
#define WORD_BUF_SIZE 32
int READ_SIZE=10;


typedef struct node{
	int doc;
	int pos;
	struct node *next;
} node;

typedef struct match_counter{
	int doc1,doc2,counter;
	struct match_counter *next;
} match_counter;

int doc_sizes[50], Len=0;

node* list[FILTER_SIZE];
unsigned int filter[FILTER_SIZE];
match_counter* count;

void load_words(char *, int);
void insert_word(char *,int, int);
void get_hashes(unsigned int[], char *);
void match(int[], int);
void string_match(node*);

int main()
{	
	int i, no_of_docs; char filename[30];
	for(i=0;i<FILTER_SIZE;i++)
		{ 
                list[i]=(node *)malloc(sizeof(node)*1);
                list[i]->next=NULL;
		//printf("%p ",list[i]);
		}

	for (i = 0; i < FILTER_SIZE; i++)
		filter[i] = 0;
	//printf("going to load words \n");

        FILE *f;
	int smaller;
	char buffer[500];
	
	f=fopen("inputToBloom.txt","r");
	fscanf(f,"%s",filename);	
	while(!feof(f))
	{// setting READ_SIZE
	 FILE *f1 = fopen(filename, "r");
	fseek(f1,0,SEEK_END);
	doc_sizes[Len++]= ftell(f1);
	fclose(f1);
	fscanf(f,"%s",filename);
	}
	smaller=READ_SIZE;

for(i=0;i<Len;i++)
	printf("%d  ",doc_sizes[i]);

	for(i=0;i<Len;i++)
	{smaller=(smaller<doc_sizes[i])?smaller:doc_sizes[i];
	}
	READ_SIZE=(READ_SIZE>smaller)?smaller:READ_SIZE;
	no_of_docs=i;
	fclose(f);

	//making concatenated file
	f=fopen("inputToBloom.txt","r");
	FILE *concatFile= fopen("ConcatenatedFile","w");
	fscanf(f,"%s",filename);	
	for(i=0;i<Len;i++)
	{
	FILE *f1 = fopen(filename, "r");
	fread(buffer,doc_sizes[i],1,f1);
	fwrite(buffer,doc_sizes[i],1,concatFile);
	fclose(f1);
	fscanf(f,"%s",filename);
	}
	fclose(concatFile);
	//printf("%d\n",no_of_docs);

	f=fopen("inputToBloom.txt","r");
	fscanf(f,"%s",filename);
	i=1;//document number	
	while(!feof(f))
	{// calling load_words
	 FILE *f1 = fopen(filename, "r");
	load_words(filename,i); //printf("%s ",filename);
	i++;
	fclose(f1);
	fscanf(f,"%s",filename); 
	}

fclose(f);

count=(match_counter*) malloc(sizeof(match_counter));
count->next=NULL;
//taking only cells with >collisions

int count_int; node *head;

for(i=0;i<FILTER_SIZE;i++)
{	node *tmp=list[i]->next;
	node *head=list[i]->next;
	if(tmp!=NULL)
	{ count_int=0;
	while(tmp->next!=NULL)
		{ 
		count_int++;
		printf("%d:%d %d \n",i,tmp->doc, tmp->pos);
		//printf("\n cell %d: \n",i);
		tmp=tmp->next;
		}
	
	if(count_int>=no_of_docs)
		string_match(head);
	}
}


// printing final counts
match_counter *m= count;

if(m->next==NULL)
	printf("No plagiarism in any documents\n");

while(m->next!=NULL)
{
	m=m->next;
	m->counter=m->counter/NUM_HASHES;
	int doc1, doc2; float percentage;
	doc1= (doc_sizes[(m->doc1)-1] - READ_SIZE);
	doc2= (doc_sizes[(m->doc2)-1] - READ_SIZE);
	printf("%d, %d Between %d and %d count is %d \n",doc1,doc2,m->doc1, m->doc2, m->counter);
	percentage= (2* (m->counter))/((float)(doc1+doc2));
	percentage= percentage*100;
	printf("Between %d and %d percentage is %f \n",m->doc1, m->doc2, percentage);

	if(percentage>50)
		printf("Plagiarism between %d and %d \n",m->doc1, m->doc2);
}


return 0;

}

void string_match(node *head)
{
	node* head1=(node*) malloc(sizeof(node));
	head1=head;
	head1=head->next; 
	FILE *concatFile= fopen("ConcatenatedFile","r");

	while(head1->next!=NULL)
		{ 
		while(head1->next!=NULL)
			{
				int ptr=0,j;char buf[50],buf1[50];
				for(j=0;j<(head->doc)-1;j++)
					ptr+=doc_sizes[j];
				ptr=ptr+(head->pos)-1;
				fseek(concatFile,ptr,SEEK_SET);				
				fread(buf,READ_SIZE,1,concatFile);
				buf[READ_SIZE]='\0';

			if(head->doc != head1->doc)
				{//printf("%d:%d with %d:%d ",head->doc,head->pos,head1->doc,head1->pos);
			//kmp call
							
				ptr=0;
				for(j=0;j<(head1->doc)-1;j++)
					ptr+=doc_sizes[j];
				ptr=ptr+(head1->pos)-1;
				fseek(concatFile,ptr,SEEK_SET);				
				fread(buf1,READ_SIZE,1,concatFile);
				buf1[READ_SIZE]='\0';

//printf("%s  .. %s\n",buf,buf1);
				if(strcmp(buf,buf1)==0)
					{
					//printf("same: %d(%d) and %d(%d)\n",head->doc,head->pos,head1->doc,head1->pos);
				
					if(count->next!=NULL)		
					{
					match_counter* t= count;
					while(t->next!=NULL)
						{
						t=t->next;
						if(t->doc1==head->doc && t->doc2==head1->doc)
						{t->counter++; }
else
{match_counter *temp_match=(match_counter*) malloc(sizeof(match_counter));
temp_match->doc1=head->doc;
temp_match->doc2=head1->doc;
temp_match->counter=1;
temp_match->next=NULL;

match_counter *t1= count;
while(t1->next!=NULL) t1=t1->next;
t1->next=temp_match;

}
						}
					}

else 
{			
match_counter *temp_match=(match_counter*) malloc(sizeof(match_counter));
temp_match->doc1=head->doc;
temp_match->doc2=head1->doc;
temp_match->counter=1;
temp_match->next=NULL;
count->next=temp_match;

}


					}
				}
			head1=head1->next;
			}
		head=head->next;
		head1=head->next;
		}
	fclose(concatFile);
}


void load_words(char *filename,int doc_no)
{			
	FILE *f = fopen(filename, "r");
	int c,k,size,upper;
        size=0;
        char read_file[READ_SIZE];
	if (!f)
		{printf("unable to open file \"%s\"\n", filename); return;}
    /*      if((fseek(f,0,SEEK_END))==-1){
          printf("ERROR: error in reading file \n");
          return;
          }
         upper=ftell(f);*/
        
upper= doc_sizes[doc_no-1]; //printf("upper= %d\n",upper);

         while(size<=(upper-(READ_SIZE)))
       {
         if((fseek(f,size,SEEK_SET))==-1)
	  {
          printf("ERROR: error in reading file \n");
          return;
          }
         
          for(k=0;k<(READ_SIZE);k++)
          { read_file[k]=fgetc(f);
         // fscanf(f,"%s",read_file);
          }
           read_file[READ_SIZE]='\0';
          //printf("%s\n",read_file);
         insert_word(read_file,doc_no, size);
 	  size=size+1;
        }

   fclose(f);
}

void insert_word( char *str, int doc_no, int size)
{
	unsigned int hash[NUM_HASHES],d;
	int i;
	//printf("in insert word fn \n");
	get_hashes(hash, str);
	//printf("returned from get hashes\n");
	for (i = 0; i < NUM_HASHES; i++) 
	{
                 hash[i]=hash[i]%97;
                 //printf("%u\n for 97\n",hash[i]);
		 filter[hash[i]]++;
		 //printf("%d ",i);
		node *temp=(node *)malloc(sizeof(node));
		temp->doc=doc_no; 	
		temp->pos=size;
		temp->next=NULL;
		
		if(list[hash[i]]->next==NULL)
		{
                
		list[hash[i]]->next=temp;
		 //int z;scanf("%d",&z);
		}
		
		else
		{node *temp1=list[hash[i]]->next;
		while(temp1->next !=NULL)
			{
			 temp1=temp1->next;
			}
		 temp1->next=temp;
		}
	}
/*
          for(i=0;i<FILTER_SIZE;i++)
          { 
             printf("%d ",list[i]->doc);       
          }
*/
}

void get_hashes(unsigned int hash[], char *in)
{       
        int i;
	unsigned char *str = (unsigned char *)in;
	//printf("%c\n",*str);
	int pos = strlen(in);
	hash[0] = RSHash  (str, pos);
	hash[1] = DJBHash (str, pos);
	hash[2] = FNVHash (str, pos);
	hash[3] = JSHash  (str, pos);
	hash[4] = PJWHash (str, pos);
	hash[5] = SDBMHash(str, pos);
	hash[6] = DEKHash (str, pos);
/*
     for(i=0;i<NUM_HASHES;i++)
       {
	printf("the value of hash[%d] is %u\n",i,hash[i]);        
	printf("%u\n",hash[i]);
        }
 */  

}


